package {
	import flash.desktop.NativeApplication;
	import flash.desktop.SystemTrayIcon;
	import flash.display.Bitmap;
	import flash.display.NativeWindowDisplayState;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.MouseEvent;
	import flash.events.NativeWindowDisplayStateEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.ServerSocketConnectEvent;
	import flash.net.ServerSocket;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	
	/**
	 * ...
	 * @author Ricardo Teixeira
	 */
	public class Main extends Sprite {
		
		
		[Embed(source='../lib/trayIcon_32.png')]
		private var TrayIcon32:Class;
		
		[Embed(source='../lib/trayIcon_48.png')]
		private var TrayIcon48:Class;
		
		[Embed(source='../lib/trayIcon_64.png')]
		private var TrayIcon64:Class;
		
		[Embed(source = '../lib/trayIcon_72.png')]
		private var TrayIcon72:Class;
		
		[Embed(source='../lib/trayIcon_128.png')]
		private var TrayIcon128:Class;
		
		private var trayIcons:Array;
		private var server:ServerSocket;
		private var porta:int;
		private var clientes:Vector.<Socket>;
		private var _numeroConexoes:Number;
		
		public function Main():void {
			
			this._numeroConexoes = 0;
			
			this.clientes = new Vector.<Socket> ();
			this.porta = 6667;
						
			this.trayIcons = new Array ();
			this.trayIcons.push ( new TrayIcon32 () as Bitmap );
			this.trayIcons.push ( new TrayIcon64 () as Bitmap );
			this.trayIcons.push ( new TrayIcon72 () as Bitmap );
			this.trayIcons.push ( new TrayIcon128 () as Bitmap );
			
			if (NativeApplication.supportsSystemTrayIcon) { 
				var sysTrayIcon:SystemTrayIcon = NativeApplication.nativeApplication.icon as SystemTrayIcon; 
				sysTrayIcon.bitmaps = this.trayIcons;
				sysTrayIcon.tooltip = "iJoy Server"; 
				sysTrayIcon.addEventListener(MouseEvent.CLICK, onUndock); 
				
				//sysTrayIcon.menu = createIconMenu();
			}
			this.stage.nativeWindow.addEventListener (NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGE, onChangeWindow);
			
			this.iniciar ();
		}
		
		/**
		 * Inicia o servidor socket e escuta as conexões.
		 */
		public function iniciar ():void{
			
			this.server = new ServerSocket ();			
			this.server.addEventListener (Event.CONNECT, onConnect);
			
			try {
				this.server.bind (this.porta);
				this.server.listen();
			} catch (e:Error) {
				trace (e.message, "Error");
			}			
		}
		
		public function broadcast (cliente:Socket):void {
			var buffer:ByteArray = new ByteArray();
			var clientSocket:Socket = cliente;
            clientSocket.readBytes( buffer, 0, clientSocket.bytesAvailable );
			
			var id:int = this.clientes.indexOf (cliente);
			
			for (var i:int = 0; i < this.clientes.length; i++) {
				clientSocket = this.clientes[i] as Socket;
				clientSocket.writeUTFBytes ( buffer.toString() );
				clientSocket.flush ();
			}
			trace (buffer.toString());
		}
		
		
		private function onConnect(e:ServerSocketConnectEvent):void {
			var cliente:Socket = Socket (e.socket);
			this.clientes.push (cliente);
			cliente.addEventListener (ProgressEvent.SOCKET_DATA, onData);
			cliente.addEventListener (Event.CLOSE, onCloseCliente);
			cliente.addEventListener (IOErrorEvent.IO_ERROR, onErrorCliente);
			cliente.addEventListener (SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			
			this._numeroConexoes ++;			
			
			trace (this._numeroConexoes );
		}
		
		private function onSecurityError(e:SecurityErrorEvent):void {
			
		}
		
		private function onErrorCliente(e:IOErrorEvent):void {
			
		}
		
		private function onCloseCliente(e:Event):void {
			var cliente:Socket = e.target as Socket;
			var id:int = this.clientes.indexOf (cliente);
			this.clientes.splice (id, 1);
			this._numeroConexoes --;
		}
		
		private function onData(e:ProgressEvent):void {
			var cliente:Socket = Socket (e.target);
			this.broadcast (cliente);
		}
		
		private function onChangeWindow(e:NativeWindowDisplayStateEvent):void {
			if (e.afterDisplayState == NativeWindowDisplayState.MINIMIZED) {
				this.stage.nativeWindow.visible = false; 
			}
		}
		
		public function onUndock (event:Event = null):void { 
			this.stage.nativeWindow.visible = true; 
			this.stage.nativeWindow.restore ();
			//NativeApplication.nativeApplication.icon.bitmaps = []; 
		}
		
	}
	
}